package com.hsh.erp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hsh.erp.constants.ResultConstants;
import com.hsh.erp.domain.common.Result;
import com.hsh.erp.domain.dto.OrderDTO;
import com.hsh.erp.domain.dto.OutboundDTO;
import com.hsh.erp.domain.entity.Order;
import com.hsh.erp.domain.entity.Outbound;
import com.hsh.erp.domain.vo.OrderVO;
import com.hsh.erp.domain.vo.OutboundVO;
import com.hsh.erp.domain.vo.StockVO;
import com.hsh.erp.mapper.OutboundMapper;
import com.hsh.erp.service.*;
import com.hsh.erp.utils.MyBeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * @author USER
 * @description 针对表【outbound】的数据库操作Service实现
 * @createDate 2024-05-30 16:21:43
 */
@Service
public class OutboundServiceImpl extends ServiceImpl<OutboundMapper, Outbound>
        implements OutboundService {
    @Resource
    private OutboundMapper outboundMapper;
    @Resource
    @Lazy
    private InOutTypeService inOutTypeService;
    @Resource
    @Lazy
    private ShopService shopService;
    @Resource
    @Lazy
    private RepositoryService repositoryService;
    @Resource
    @Lazy
    private ProductService productService;
    @Resource
    private OrderService orderService;
    @Resource
    private StockService stockService;

    /**
     * 列表查询
     *
     * @param outboundVO
     * @return
     */
    @Override
    public Result<List<OutboundDTO>> getList(OutboundVO outboundVO) {
        // 初始化参数并查询
        List<OutboundDTO> outboundDTOList = outboundMapper.getOutboundDTOList(outboundVO.selectInit());
        // 获取供应商名称，仓库名称，产品名称
        for (OutboundDTO outboundDTO : outboundDTOList) {
            outboundDTO.init()
                    .setTypeName(inOutTypeService.getNameById(outboundDTO.getTypeId()))
                    .setShopName(shopService.getNameById(outboundDTO.getShopId()))
                    .setRepositoryName(repositoryService.getNameById(outboundDTO.getRepositoryId()))
                    .setProductName(productService.getNameById(outboundDTO.getProductId()));
        }

        return Result.success(outboundDTOList);
    }


    /**
     * 修改一条记录
     *
     * @param outboundVO
     * @return
     */
    @Override
    public Result updateOne(OutboundVO outboundVO) {
        // 查找要修改的出库记录
        Outbound oldOutbound = getById(outboundVO.getId());

        if (oldOutbound == null) {
            // 旧记录不存在
            return Result.fail(ResultConstants.FAIL_RECORD_NOT_EXIST);
        }

        // 根据 no+productId+repositoryId 查找 订单
        Order order = orderService.getOneByQuery(MyBeanUtils.copy(outboundVO, OrderVO.class));
        // no+productId+repositoryId 在order 表中存在，无法修改
        if (order != null) {
            String orderNo = order.getNo();
            return Result.fail(String.format(ResultConstants.UPDATE_FAIL_BINDING_ORDER, outboundVO.getNo(), orderNo));
        }
        // 修改出库记录 + 修改库存
        boolean updateOutbound = updateOutbound(outboundVO, oldOutbound);

        return Result.create(updateOutbound);
    }

    /**
     * 修改出库记录 + 修改库存
     *
     * @param outboundVO
     * @param oldOutbound
     * @return
     */
    public boolean updateOutbound(OutboundVO outboundVO, Outbound oldOutbound) {
        // 修改出库记录
        outboundVO.updateInit();
        boolean updateOutbound = updateById(MyBeanUtils.copy(outboundVO, Outbound.class));

        // 修改库存
        boolean updateStock;
        // 修改的参数
        Integer productId = outboundVO.getProductId();
        Integer repositoryId = outboundVO.getRepositoryId();
        Integer actualNum = outboundVO.getActualNum();
        Integer isDelete = outboundVO.getIsDelete();
        // 旧订单参数
        Integer oldProductId = oldOutbound.getProductId();
        Integer oldRepositoryId = oldOutbound.getRepositoryId();
        Integer oldActualNum = oldOutbound.getActualNum();
        Integer oldIsDelete = oldOutbound.getIsDelete();
        // 修改出库记录逻辑
        if (oldIsDelete < isDelete) {
            // 删除记录，未删除->删除，恢复 旧出库 库存
            updateStock = stockService.updateOrAddNumByQuery(new StockVO(oldProductId, oldRepositoryId, oldActualNum));
        } else if (oldIsDelete > isDelete) {
            // 恢复记录，删除->未删除，减掉 新出库 库存
            updateStock = stockService.updateOrAddNumByQuery(new StockVO(oldProductId, oldRepositoryId, -1 * oldActualNum));
        } else if (oldIsDelete != 0) {
            // 修改已删除的记录，无需改变库存
            updateStock = true;
        } else if (oldProductId == productId && oldRepositoryId == repositoryId) {
            // 修改未删除的订单--修改前后 productId+repositoryId 一致，直接修改库存 -1 *（newNum - oldNum）
            updateStock = stockService.updateOrAddNumByQuery(new StockVO(productId, repositoryId, -1 * (actualNum - oldActualNum)));
        } else {// 修改未删除的订单--修改前后 productId+repositoryId 不一致，
            // 恢复 旧出库 库存
            boolean delete = stockService.updateOrAddNumByQuery(new StockVO(oldProductId, oldRepositoryId, oldActualNum));
            // 减掉 新出库 库存
            boolean add = stockService.updateOrAddNumByQuery(new StockVO(productId, repositoryId, -1 * actualNum));
            updateStock = delete && add;
        }

        // 修改出库单的完成状态
        updateIsFinish(outboundVO);

        return updateOutbound && updateStock;
    }

    private List<OrderDTO> getListByQuery(OutboundVO outboundVO) {
        QueryWrapper wrapper = new QueryWrapper<>()
                .eq("no", outboundVO.getNo())
                .eq("product_id", outboundVO.getProductId())
                .eq("repository_id", outboundVO.getRepositoryId())
                .eq("is_delete", outboundVO);
        List<OrderDTO> orderDTOList = MyBeanUtils.copyList(orderService.list(wrapper), OrderDTO.class);
        return null;
    }

    /**
     * 删除一条记录
     *
     * @param outboundVO
     * @return
     */
    @Override
    public Result deleteOne(OutboundVO outboundVO) {
        return updateOne(outboundVO);
    }

    /**
     * 新增一条记录
     *
     * @param outboundVO
     * @return
     */
    @Override
    public Result addOne(OutboundVO outboundVO) {
        outboundVO.addInit();
        boolean save = save(MyBeanUtils.copy(outboundVO, Outbound.class));
        stockService.updateOrAddNumByQuery(new StockVO(outboundVO.getProductId(), outboundVO.getRepositoryId(), -1 * outboundVO.getActualNum()));
        // 更新完成状态
        updateIsFinish(outboundVO);
        return Result.create(save);
    }

    /**
     * 批量新增
     *
     * @param outboundVOList
     * @return
     */
    @Override
    public Result addList(List<OutboundVO> outboundVOList) {
        int addNum = 0;
        for (OutboundVO outboundVO : outboundVOList) {
            addNum = addOne(outboundVO).isSuccess() ? ++addNum : addNum;
        }
        return Result.create(addNum);
    }

    /**
     * 指定时间内的出库总数量，并按产品+仓库（可选）分组
     *
     * @param outboundVO
     * @return
     */
    @Override
    public List<OutboundDTO> getOutNumByTime(OutboundVO outboundVO) {
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.select("product_id", "repository_id", "SUM(actual_num) actual_num");

        wrapper.ge(!Objects.isNull(outboundVO.getStartTime()), "create_time", outboundVO.getStartTime());
        wrapper.le(!Objects.isNull(outboundVO.getEndTime()), "create_time", outboundVO.getEndTime());

        wrapper.eq("is_delete", outboundVO.getIsDelete());
        wrapper.groupBy("product_id");

        if (outboundVO.getRepositoryId() != null && outboundVO.getRepositoryId() == -1) {
            // 查询所有仓库总库存时，仓库id设置为-1
            wrapper.select("product_id", "-1 repository_id", "SUM(actual_num) actual_num");
        } else if (outboundVO.getRepositoryId() == null) {
            // 查询各仓库时
            wrapper.groupBy("repository_id");
        } else {
            // 查询具体仓库时
            wrapper.eq("repository_id", outboundVO.getRepositoryId());
            wrapper.groupBy("repository_id");
        }

        return MyBeanUtils.copyList(list(wrapper), OutboundDTO.class);
    }

    /**
     * 根据no+productId+repositoryId
     * 修改idDelete 和 note
     *
     * @param order
     * @return
     */
    @Override
    public boolean deleteByOrder(Order order) {
        UpdateWrapper wrapper = new UpdateWrapper();
        wrapper.set("is_delete", order.getIsDelete());
        wrapper.set("note", order.getNote());
        wrapper.eq("no", order.getNo());
        wrapper.eq("product_id", order.getProductId());
        wrapper.eq("repository_id", order.getRepositoryId());

        // 删除出库记录
        boolean deleteOutbound = update(wrapper);

        // 库存加上 该出库记录 的出货数量
        boolean updateStock = stockService.updateOrAddNumByQuery(new StockVO(order.getProductId(), order.getRepositoryId(), order.getActualNum()));

        return deleteOutbound && updateStock;
    }

    //============================================私有方法开始============================================

    /**
     * 同步更新 no+productId+repositoryId 相同的
     * 完成状态 和 计划出库数量
     *
     * @param outboundVO
     */
    private void updateIsFinish(OutboundVO outboundVO) {
        // 查找 no+productId+repositoryId 相同的记录
        List<Outbound> outboundList = list(new QueryWrapper<Outbound>()
                .eq("no", outboundVO.getNo())
                .eq("product_id", outboundVO.getProductId())
                .eq("repository_id", outboundVO.getRepositoryId())
                .eq("is_delete", 0));
        // 统计 实际出库总数量
        Map<String, Integer> outNumMap = outboundList.stream()
                .collect(Collectors.toMap(
                        v -> v.getNo() + "-" + v.getProductId() + "-" + v.getRepositoryId()
                        , v -> v.getActualNum() == null ? 0 : v.getActualNum()
                        , Integer::sum));
        // 为所有 no+productId+repositoryId 相同的记录更新 完成状态 和 计划出库数量
        for (Outbound outbound : outboundList) {
            int actualSum = outNumMap.get(outbound.getNo() + "-" + outbound.getProductId() + "-" + outbound.getRepositoryId());
            int isFinish = outboundVO.getPlanNum() > actualSum ? 0 : 1;
            // 保留需要修改 完成状态 和 计划出库数量 的记录
            UpdateWrapper wrapper = new UpdateWrapper();

            wrapper.set("plan_num", outboundVO.getPlanNum());
            wrapper.set("is_finish", isFinish);

            wrapper.eq("no", outbound.getNo());
            wrapper.eq("product_id", outbound.getProductId());
            wrapper.eq("repository_id", outbound.getRepositoryId());
            update(wrapper);

        }

    }
    //============================================私有方法结束============================================
}




